package com.apikey.auth.service.impl;

import com.apikey.auth.config.ApplicationLimitProperties;
import com.apikey.auth.entity.Application;
import com.apikey.auth.repository.ApplicationRepository;
import com.apikey.auth.service.ApplicationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * API Key申请服务实现类
 * 提供申请相关的业务逻辑实现
 *
 * @author API Key Framework
 * @version 1.0
 */
@Service
@Transactional
public class ApplicationServiceImpl implements ApplicationService {

    @Autowired
    private ApplicationRepository applicationRepository;

    @Autowired
    private ApplicationLimitProperties applicationLimitProperties;

    /**
     * 提交API Key申请
     *
     * @param phoneNumber    手机号
     * @param verifyPassword 验证密码（可选）
     * @param fingerprint    浏览器指纹
     * @param remark         申请说明
     * @return 申请记录
     */
    @Override
    public Application submitApplication(String phoneNumber, String verifyPassword, String fingerprint, String remark) {
        // 验证参数
        validateApplicationParams(phoneNumber, verifyPassword, fingerprint);
        
        // 检查浏览器指纹申请数量限制
        long currentCount = applicationRepository.countByFingerprint(fingerprint);
        int maxApplications = applicationLimitProperties.getMaxApplicationsPerFingerprint();
        
        if (currentCount >= maxApplications) {
            throw new RuntimeException("该设备申请数量已达上限，最多可申请" + maxApplications + "个API Key");
        }
        
        // 创建申请记录（移除重复申请限制，允许同一手机号多次申请）
        Application application = new Application();
        application.setPhoneNumber(phoneNumber);
        application.setVerifyPassword(verifyPassword);
        application.setFingerprint(fingerprint);
        application.setRemark(remark);
        application.setStatus(Application.Status.PENDING.getCode());
        application.setApplyTime(LocalDateTime.now());
        
        return applicationRepository.save(application);
    }

    /**
     * 根据手机号和验证密码查询申请状态
     *
     * @param phoneNumber    手机号
     * @param verifyPassword 验证密码
     * @return 申请记录列表
     */
    @Override
    @Transactional(readOnly = true)
    public List<Application> queryApplicationByPhone(String phoneNumber, String verifyPassword) {
        validateQueryParams(phoneNumber, verifyPassword);
        
        if (StringUtils.hasText(verifyPassword)) {
            return applicationRepository.findByPhoneNumberAndVerifyPasswordOrderByApplyTimeDesc(phoneNumber, verifyPassword);
        } else {
            // 如果没有验证密码，查找该手机号的所有申请记录
            return applicationRepository.findByPhoneNumberOrderByApplyTimeDesc(phoneNumber);
        }
    }

    /**
     * 根据浏览器指纹查询申请状态
     *
     * @param fingerprint 浏览器指纹
     * @return 申请记录列表
     */
    @Override
    @Transactional(readOnly = true)
    public List<Application> queryApplicationsByFingerprint(String fingerprint) {
        if (!StringUtils.hasText(fingerprint)) {
            throw new IllegalArgumentException("浏览器指纹不能为空");
        }
        
        return applicationRepository.findByFingerprintOrderByApplyTimeDesc(fingerprint);
    }

    /**
     * 根据ID查询申请记录
     *
     * @param id 申请ID
     * @return 申请记录
     */
    @Override
    @Transactional(readOnly = true)
    public Optional<Application> findById(Long id) {
        if (id == null) {
            throw new IllegalArgumentException("申请ID不能为空");
        }
        return applicationRepository.findById(id);
    }

    /**
     * 获取待审核的申请列表
     *
     * @param pageable 分页参数
     * @return 待审核申请分页结果
     */
    @Override
    @Transactional(readOnly = true)
    public Page<Application> getPendingApplications(Pageable pageable) {
        return applicationRepository.findByStatus(Application.Status.PENDING, pageable);
    }

    /**
     * 获取所有申请列表
     *
     * @param pageable 分页参数
     * @return 申请分页结果
     */
    @Override
    @Transactional(readOnly = true)
    public Page<Application> getAllApplications(Pageable pageable) {
        return applicationRepository.findAll(pageable);
    }

    /**
     * 根据状态查询申请列表
     *
     * @param status   申请状态
     * @param pageable 分页参数
     * @return 申请分页结果
     */
    @Override
    @Transactional(readOnly = true)
    public Page<Application> getApplicationsByStatus(Application.Status status, Pageable pageable) {
        if (status == null) {
            throw new IllegalArgumentException("申请状态不能为空");
        }
        return applicationRepository.findByStatus(status, pageable);
    }

    /**
     * 根据手机号查询申请记录
     *
     * @param phoneNumber 手机号
     * @return 申请记录列表
     */
    @Override
    @Transactional(readOnly = true)
    public List<Application> findByPhoneNumber(String phoneNumber) {
        if (!StringUtils.hasText(phoneNumber)) {
            throw new IllegalArgumentException("手机号不能为空");
        }
        return applicationRepository.findByPhoneNumberOrderByApplyTimeDesc(phoneNumber);
    }

    /**
     * 根据审核人查询申请记录
     *
     * @param reviewer 审核人
     * @param pageable 分页参数
     * @return 申请分页结果
     */
    @Override
    @Transactional(readOnly = true)
    public Page<Application> findByReviewer(String reviewer, Pageable pageable) {
        if (!StringUtils.hasText(reviewer)) {
            throw new IllegalArgumentException("审核人不能为空");
        }
        return applicationRepository.findByReviewer(reviewer, pageable);
    }

    /**
     * 根据时间范围查询申请记录
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @param pageable  分页参数
     * @return 申请分页结果
     */
    @Override
    @Transactional(readOnly = true)
    public Page<Application> findByTimeRange(LocalDateTime startTime, LocalDateTime endTime, Pageable pageable) {
        if (startTime == null || endTime == null) {
            throw new IllegalArgumentException("开始时间和结束时间不能为空");
        }
        if (startTime.isAfter(endTime)) {
            throw new IllegalArgumentException("开始时间不能晚于结束时间");
        }
        return applicationRepository.findByApplyTimeBetween(startTime, endTime, pageable);
    }

    /**
     * 统计不同状态的申请数量
     *
     * @return 状态统计Map
     */
    @Override
    @Transactional(readOnly = true)
    public Map<Application.Status, Long> getStatusStatistics() {
        return Arrays.stream(Application.Status.values())
                .collect(Collectors.toMap(
                        status -> status,
                        status -> applicationRepository.countByStatus(status.getCode())
                ));
    }

    /**
     * 获取最近的申请记录
     *
     * @param limit 限制数量
     * @return 最近申请列表
     */
    @Override
    @Transactional(readOnly = true)
    public List<Application> getRecentApplications(int limit) {
        if (limit <= 0) {
            throw new IllegalArgumentException("限制数量必须大于0");
        }
        Pageable pageable = PageRequest.of(0, limit, Sort.by(Sort.Direction.DESC, "applyTime"));
        return applicationRepository.findRecentApplications(pageable);
    }

    /**
     * 检查手机号是否有待审核或已通过的申请
     * 注意：此方法仅用于统计和查询目的，不再用于限制申请提交
     *
     * @param phoneNumber 手机号
     * @return 是否存在
     */
    @Override
    @Transactional(readOnly = true)
    public boolean hasActiveApplicationByPhone(String phoneNumber) {
        if (!StringUtils.hasText(phoneNumber)) {
            return false;
        }
        return applicationRepository.existsByPhoneNumberAndStatusIn(phoneNumber, 
                Arrays.asList("PENDING", "APPROVED"));
    }

    /**
     * 检查浏览器指纹是否有待审核或已通过的申请
     * 注意：此方法仅用于统计和查询目的，不再用于限制申请提交
     *
     * @param fingerprint 浏览器指纹
     * @return 是否存在
     */
    @Override
    @Transactional(readOnly = true)
    public boolean hasActiveApplicationByFingerprint(String fingerprint) {
        if (!StringUtils.hasText(fingerprint)) {
            return false;
        }
        return applicationRepository.existsByFingerprintAndStatusIn(fingerprint, 
                Arrays.asList("PENDING", "APPROVED"));
    }

    /**
     * 验证申请参数
     *
     * @param phoneNumber    手机号
     * @param verifyPassword 验证密码
     * @param fingerprint    浏览器指纹
     * @throws IllegalArgumentException 参数验证失败时抛出
     */
    @Override
    public void validateApplicationParams(String phoneNumber, String verifyPassword, String fingerprint) {
        if (!StringUtils.hasText(phoneNumber)) {
            throw new IllegalArgumentException("手机号不能为空");
        }
        
        // 验证手机号格式
        if (!phoneNumber.matches("^1[3-9]\\d{9}$")) {
            throw new IllegalArgumentException("手机号格式不正确");
        }
        
        // 验证密码长度（如果提供）
        if (StringUtils.hasText(verifyPassword) && verifyPassword.length() < 6) {
            throw new IllegalArgumentException("验证密码长度不能少于6位");
        }
        
        // 验证浏览器指纹（如果提供）
        if (StringUtils.hasText(fingerprint) && fingerprint.length() < 10) {
            throw new IllegalArgumentException("浏览器指纹格式不正确");
        }
    }

    /**
     * 验证查询参数
     *
     * @param phoneNumber    手机号
     * @param verifyPassword 验证密码
     * @throws IllegalArgumentException 参数验证失败时抛出
     */
    @Override
    public void validateQueryParams(String phoneNumber, String verifyPassword) {
        if (!StringUtils.hasText(phoneNumber)) {
            throw new IllegalArgumentException("手机号不能为空");
        }
        
        // 验证手机号格式
        if (!phoneNumber.matches("^1[3-9]\\d{9}$")) {
            throw new IllegalArgumentException("手机号格式不正确");
        }
    }
}